﻿using SearchInFiles.Global;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace SearchInFiles.Lib.Tools
{
    public class UtilityTools
    {
        public static void SetSearchHistory(string NewValue)
        {
            int index = -1;
            //在历史记录中搜索
            for (int i = 0; i < Config.Instance.SearchHistory.Count; i++)
                if (Config.Instance.SearchHistory[i].Equals(NewValue, StringComparison.OrdinalIgnoreCase))
                { index = i; break; }
            //没搜到-添加
            if (index < 0)
            {
                Config.Instance.SearchHistory.Insert(0, NewValue);
                if (Config.Instance.SearchHistory.Count > 10)
                {
                    for (int i = Config.Instance.SearchHistory.Count - 1; i > 9; i--)
                        Config.Instance.SearchHistory.RemoveAt(i);
                }
                Config.Save();
                return;
            }
            //搜到-移动
            Config.Instance.SearchHistory.Move(index, 0);
            Config.Save();
        }
        public static IEnumerable<T> GetChilds<T>(DependencyObject SourceElement) where T : DependencyObject
        {
            Queue<DependencyObject> CacheQueue = new Queue<DependencyObject>();
            CacheQueue.Enqueue(SourceElement);
            DependencyObject Current;
            int Count;
            while (CacheQueue.Count > 0)
            {
                Current = CacheQueue.Dequeue();
                if (Current is T Result)
                    yield return Result;
                Count = VisualTreeHelper.GetChildrenCount(Current);
                while (Count-- > 0)
                    CacheQueue.Enqueue(VisualTreeHelper.GetChild(Current, Count));
            }
            yield break;
        }

        public static bool GetParent<T>(DependencyObject SourceElement, out T? Result) where T : DependencyObject
        {
            DependencyObject current = SourceElement;
            Result = null;
            while (current != null)
            {
                if (current is T Parent)
                {
                    Result = Parent;
                    return true;
                }
                try { current = VisualTreeHelper.GetParent(current); }
                catch { return false; }
            }
            return false;
        }

        public static IEnumerable<DependencyObject> GetChildsByTypeName(DependencyObject SourceElement, string TarTypeName)
        {
            Queue<DependencyObject> CacheQueue = new Queue<DependencyObject>();
            CacheQueue.Enqueue(SourceElement);
            DependencyObject Current;
            int Count;
            while (CacheQueue.Count > 0)
            {
                Current = CacheQueue.Dequeue();
                if (Current.GetType().Name.Equals(TarTypeName, StringComparison.OrdinalIgnoreCase))
                    yield return Current;
                Count = VisualTreeHelper.GetChildrenCount(Current);
                while (Count-- > 0)
                    CacheQueue.Enqueue(VisualTreeHelper.GetChild(Current, Count));
            }
            yield break;
        }

        public static ParallelQuery<T> SetParallelMode<T>(IEnumerable<T> source, CancellationTokenSource cancellationTokenSource, int TaskProcessingCapacity, int? ProcessorCount = null)
        {
            if (ProcessorCount == null) 
                ProcessorCount = Environment.ProcessorCount;

            ParallelQuery<T> p = source.AsParallel();
            int ElementCount = source.Count();
            if (ElementCount < TaskProcessingCapacity)
                return p;

            return p.WithExecutionMode(ParallelExecutionMode.ForceParallelism).WithCancellation(cancellationTokenSource.Token)
                .WithDegreeOfParallelism(Math.Min(ProcessorCount.Value, (int)Math.Ceiling((double)ElementCount / TaskProcessingCapacity)));
        }

        public static int AvailableProcessorCount()
        {
            using (CPUHelper cpuHelper = new CPUHelper())
            {
                int PhysicalCoreCount = CPUHelper.CPUCoreCount();
                int IdleLogicalCore = cpuHelper.GetCPUUsage().Where(p => p < 60).Count();
                IdleLogicalCore = Math.Min(PhysicalCoreCount, IdleLogicalCore / 2);
                PhysicalCoreCount = IdleLogicalCore < PhysicalCoreCount ? IdleLogicalCore : PhysicalCoreCount - 1;
                return PhysicalCoreCount > 1 ? PhysicalCoreCount : 1;
            }
        }

        public static void ExplorerProcessStart(string Path) => ProcessStart("Explorer", $"/select, {Path}");
        public static void OpenWith(string Path) => ProcessStart("rundll32", $"shell32,OpenAs_RunDLL {Path}");
        public static void NotepadOpen(string Path) => ProcessStart("notepad", Path);
        public static void DefaultOpen(string Path) => ProcessStart(Path);
        public static void CopyFileToClipboard(params string[] Paths) { StringCollection sc = new StringCollection(); sc.AddRange(Paths); Clipboard.Clear(); Clipboard.SetFileDropList(sc); }
        public static void CopyStringToClipboard(string text) { Clipboard.Clear(); Clipboard.SetText(text); }
        public static void CopyPathsToClipboard(params string[] Paths) { Clipboard.Clear(); Clipboard.SetText(string.Join("\r\n", Paths)); }

        private static void ProcessStart(string StartUP, string? Argument = null)
        {
            using(Process p = new Process()) 
            {
                p.StartInfo.FileName = StartUP;
                p.StartInfo.Arguments = Argument;
                p.StartInfo.UseShellExecute = true;
                p.StartInfo.CreateNoWindow = false;
                p.Start();
            }
        }
    }
}
